#pragma once
#include <iostream>
#include <list>
#include <memory>
#include <algorithm>

#include "Log.hpp"
#include "InetAddr.hpp"
#include "MyMutex.hpp"
#include "Common.hpp"

namespace UserArea
{
    using namespace LogArea;
    using namespace MyMutexArea;

    class UserInterface
    {
    public:
        virtual ~UserInterface() = default;
        virtual void SendTo(int sockfd, const std::string &message) = 0;
        virtual bool operator==(const InetAddr &id) = 0;
        virtual std::string Id() = 0;
    };

    // 用户
    class User : public UserInterface
    {
    public:
        User(const InetAddr &id) : _id(id)
        {
        }

        void SendTo(int sockfd, const std::string &message) override
        {
            LOG(LogLevel::INFO) << "send message to: " << _id.Addr() << "message: " << message;
            // 服务器向客户端转送信息的接口
            ssize_t n = ::sendto(sockfd, message.c_str(), message.size(), 0, _id.NetAddr(), _id.SockLen());
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "sendto error";
                DIE(SENDTO_ERR);
            }
        }

        bool operator==(const InetAddr &id) override
        {
            return _id == id;
        }

        std::string Id() override
        {
            return _id.Addr();
        }
        ~User()
        {
        }

    private:
        InetAddr _id;
    };

    // 将用户管理起来, 先描述, 再组织
    class UserManager
    {
    public:
        UserManager()
        {
        }

        void AddUser(InetAddr &id)
        {
            LockGuard lockguard(_mutex);
            for (auto &it : _user_list)
            {
                if (*it == id)
                {
                    LOG(LogLevel::INFO) << id.Addr() << "该用户已经存在";
                    return;
                }
            }
            LOG(LogLevel::INFO) << "新增用户, ip: " << id.NetAddr();
            _user_list.push_back(std::make_shared<User>(id));

            PrintUser();
        }

        void RemoveUser(InetAddr &id)
        {
            //remove_if 的作用是将目标元素移到链表末尾, 并没有真正删除, 但是遍历时就无法遍历这个元素了,
            auto pos = std::remove_if(_user_list.begin(), _user_list.end(), [&id](std::shared_ptr<UserInterface> &user)
                                      { return *user == id; });
            _user_list.erase(pos,_user_list.end());
            PrintUser();
        }

        // 向所有用户转送消息
        void Router(int sockfd, const std::string &message)
        {
            LockGuard lockguard(_mutex);
            for (auto &it : _user_list)
                it->SendTo(sockfd, message);
        }

        // 打印在线用户
        void PrintUser()
        {
            for (auto it : _user_list)
                LOG(LogLevel::INFO) << "在线用户: " << it->Id();
        }
        ~UserManager()
        {
        }

    private:
        // 管理用户的链表
        std::list<std::shared_ptr<UserInterface>> _user_list;
        MyMutex _mutex;
    };
}
